package com.kbs.im.client.bootstrap;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * Netty客户端启动类
 *
 * @author zhangzhang
 */
public class ImClientBootStrap {

    /**
     * 日志记录器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ImClientBootStrap.class);

    /**
     * 客户端启动类实例
     */
    public static final ImClientBootStrap INSTANCE = new ImClientBootStrap();

    /**
     * 最大重连次数
     */
    private static final int MAX_RETRY = 5;

    /**
     * 服务器地址
     */
    private static final String HOST = "localhost";

    /**
     * 服务器端口号
     */
    private static final int PORT = 6666;

    /**
     * 客户端启动辅助实例
     */
    private final Bootstrap BOOTSTRAP = new Bootstrap();

    /**
     * 工作线程组
     */
    private final NioEventLoopGroup WORK_GROUP = new NioEventLoopGroup();


    /**
     * 启动客户端
     */
    public void run() {
        try {
            this.BOOTSTRAP
                    .group(WORK_GROUP)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(ImClientChannelInitializer.INSTANCE);
            connect(BOOTSTRAP, HOST, PORT, MAX_RETRY);
        } catch (Exception e) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("客户端启动异常！", e);
            }
        }
    }

    /**
     * 与服务器建立连接
     * 连接失败后会进行 retry 次重连
     * 每次重连时间间隔为2的n次幂秒
     *
     * @param bootstrap 启动辅助
     * @param host      服务器地址
     * @param port      服务器端口号
     * @param retry     最大重连次数
     */
    private static void connect(Bootstrap bootstrap, String host, int port, int retry) {
        bootstrap.connect(host, port).addListener(future -> {
            if (future.isSuccess()) {
                LOGGER.info("连接成功！服务器地址：{}:{}", host, port);
            } else if (retry == 0) {
                LOGGER.warn("已经尝试 {} 次连接，未能成功连接到服务器...放弃连接！", MAX_RETRY);
            } else {
                // 第几次重连
                int order = (MAX_RETRY - retry) + 1;
                // 本次重连的间隔
                int delay = 1 << order;
                LOGGER.warn("连接失败，正在进行第 {} 次重连...", order);
                LOGGER.info("正在连接服务器，服务器地址：{}:{}", host, port);
                bootstrap.config().group().schedule(() ->
                        connect(bootstrap, host, port, retry - 1), delay, TimeUnit.SECONDS);
            }
        });
    }


}
